var tgd = tgd || {};
tgd.Math = tgd.Math || {};

/* http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes */

tgd.Math.SieveOfEratosthenes = function (n, callback) {
	this._max = n;
	this._primes = [];
	this._isPrime = [];
	this._callback = callback;

	//loop variables
	this._current = 2;

	var temp = [];

	for (var i = 0; i <= this._max; this._isPrime[i] = true, temp[i++] = i);

	if (typeof tgd.Math.SieveOfEratosthenes._initialized == "undefined") {

		tgd.Math.SieveOfEratosthenes.prototype.getNumPrimes = function() {
			return this._primes.length;
		}

		tgd.Math.SieveOfEratosthenes.prototype.getIthPrime = function(i) {
			return this._primes[i];
		}

		tgd.Math.SieveOfEratosthenes.prototype.isPrime = function(num) {
			return this._isPrime[num];
		}

		tgd.Math.SieveOfEratosthenes.prototype.toString = function() {
			return this._primes.join(", ");
		}

		tgd.Math.SieveOfEratosthenes._initialized = true;
	}

	this._current = 2;
	this._primes.push(2);
	this._isPrime[0] = this._isPrime[1] = false;

	var self = this;

	var calculatePrimes = function() {
		if (Math.pow(self._current, 2) <= self._max) {  //todo: check for rounding and boundary cases
			for (var i = 2; i <= parseInt(self._max / self._current); ++i) {
				self._isPrime[i * self._current] = false;
			}

			do {
				++self._current
			} while (!self._isPrime[self._current] && self._current <= self._max)

			if (self._current <= self._max) {
				self._primes.push(self._current);
			}

			setTimeout(calculatePrimes, 0);
		} else {
			for (var i = self._current + 1; i <= self._max; ++i) {
				if (self._isPrime[i]) {
					self._primes.push(i);
				}
			}

			self._callback();
		}
	};

	setTimeout(calculatePrimes, 0);
}